/* ===================

AX2E (AXESCON XACML 2.0 Engine) is the Java authorization engine, which implements OASIS XACML 2.0 standard.
Copyright (C) 2007 AXESCON LLC

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA


Contact: AXESCON LLC - info{at}axescon.com

 =================== */
package axescon.xacml.xb.ctx.attr.factory;

import axescon.xacml.api.ExpressionEvalIndeterminateException;
import axescon.xacml.model.ctx.AttributeValue;
import axescon.xacml.model.shared.attr.DayTimeDurationAttribute;
import axescon.xacml.xb.ctx.XBAttributeValueFactory;
import org.apache.xmlbeans.GDuration;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlDuration;
import org.apache.xmlbeans.XmlException;
import x0ContextSchemaOs.oasisNamesTcXacml2.AttributeValueType;

import java.util.ArrayList;
import java.util.regex.Pattern;

/**
 * Created by IntelliJ IDEA.
 * User: argyn
 * Date: Jun 18, 2005
 * Time: 2:19:37 PM
 * Responsibilities: parses XML to instantiate the type
 * the type is based XSL duration type,
 * see http://www.w3.org/TR/2002/WD-xquery-operators-20020816/#dt-yearMonthDuration
 */
public class DayTimeDurationXBAttrValueFactory implements XBAttributeValueFactory {

    /**
     * Pattern from
     * http://www.w3.org/TR/2002/WD-xquery-operators-20020816/#dt-dayTimeDuration
     */
    private static final String patternDefinition =
            "[-]?P(\\p{Nd}D(T(\\p{Nd}+(H(\\p{Nd}+(M(\\p{Nd}+(\\.\\p{Nd}*)?S" +
            "|\\.\\p{Nd}+S)?|(\\.\\p{Nd}*)?S)|(\\.\\p{Nd}*)?S)?|M(\\p{Nd}+" +
            "(\\.\\p{Nd}*)?S|\\.\\p{Nd}+S)?|(\\.\\p{Nd}*)?S)|\\.\\p{Nd}+S))?" +
            "|T(\\p{Nd}+(H(\\p{Nd}+(M(\\p{Nd}+(\\.\\p{Nd}*)?S|\\.\\p{Nd}+S)?" +
            "|(\\.\\p{Nd}*)?S)|(\\.\\p{Nd}*)?S)?|M(\\p{Nd}+(\\.\\p{Nd}*)?S|\\.\\p{Nd}+S)?" +
            "|(\\.\\p{Nd}*)?S)|\\.\\p{Nd}+S))";

    private static Pattern pattern;

    static {
        pattern = Pattern.compile(patternDefinition);
    }

/*
    public AttributeValue toAttributeValueType(YearMonthDurationAttribute v) {
        AttributeValue ret = AttributeValue.Factory.newInstance();
        XmlCursor xmlCursor = ret.newCursor();
        xmlCursor.toNextToken();
        xmlCursor.insertChars(v.encode());
        xmlCursor.dispose();
        return ret;
    }

                    public AttributeValue toAttributeValueType(AttributeValue v) {
                        return toAttributeValueType((YearMonthDurationAttribute)v);
                    }

*/

    public DayTimeDurationAttribute getDayTimeDurationAttributeValue(AttributeValueType vt) {
        XmlCursor xmlCursor = vt.newCursor();
//        xmlCursor.toNextToken();
        xmlCursor.toFirstContentToken();

        String str = xmlCursor.getChars();

/* TODO: FIX why this pattern doesn't match anything?
        if (!pattern.matcher(str).matches())
            throw new IllegalArgumentException("DayTimeDuration doesn't match: " + str);
*/
        try {
            GDuration dur = XmlDuration.Factory.parse(vt.xmlText()).getGDurationValue();
            return new DayTimeDurationAttribute(dur.getSign(),
                    dur.getDay(),
                    dur.getHour(),
                    dur.getMinute(),
                    dur.getSecond());
        } catch (XmlException e) {
            throw new IllegalArgumentException("XmlDuration doesn't match: " + str + e);
        }


    }


    public AttributeValue getAttributeValue(AttributeValueType vt) {
        return getDayTimeDurationAttributeValue(vt);
    }


    public axescon.xacml.model.policy.AttributeValue getAttributeValue(x0PolicySchemaOs.oasisNamesTcXacml2.AttributeValueType vt) {
        return getDayTimeDurationAttributeValue(vt);
    }


    public DayTimeDurationAttribute getDayTimeDurationAttributeValue(x0PolicySchemaOs.oasisNamesTcXacml2.AttributeValueType vt) {
        XmlCursor xmlCursor = vt.newCursor();
//        xmlCursor.toNextToken();
        xmlCursor.toFirstContentToken();

        String str = xmlCursor.getChars();

/* TODO: FIX why this pattern doesn't match anything?
        if (!pattern.matcher(str).matches())
            throw new IllegalArgumentException("DayTimeDuration doesn't match: " + str);
*/
        try {
            GDuration dur = XmlDuration.Factory.parse(vt.xmlText()).getGDurationValue();
            return new DayTimeDurationAttribute(dur.getSign(),
                    dur.getDay(),
                    dur.getHour(),
                    dur.getMinute(),
                    dur.getSecond());
        } catch (XmlException e) {
            throw new IllegalArgumentException("XmlDuration doesn't match: " + str + e);
        }


    }


    public axescon.xacml.model.policy.AttributeValue[] getAttributeValues(XmlCursor cur) throws ExpressionEvalIndeterminateException {
        if (!cur.hasNextSelection()) return null;
        ArrayList ret = new ArrayList(1);
        while (cur.hasNextSelection()) {
            cur.toNextSelection();
            try {
                GDuration dur = XmlDuration.Factory.parse(cur.xmlText()).getGDurationValue();
                DayTimeDurationAttribute dtdur = new DayTimeDurationAttribute(dur.getSign(),
                        dur.getDay(),
                        dur.getHour(),
                        dur.getMinute(),
                        dur.getSecond());

                ret.add(dtdur);
            } catch (XmlException e) {
                throw new ExpressionEvalIndeterminateException(e);
            }
        }
        return (axescon.xacml.model.policy.AttributeValue[]) ret.toArray(new axescon.xacml.model.policy.AttributeValue[ret.size()]);
    }
}
